package com.frank.loadinglibrary.common;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

public class LocatingLoadingComponent extends BaseLoadingComponent {

    private Paint mPaint = new Paint();

    private Paint bottomOvalPaint = new Paint();

    private String backgroundColor = "#5d97ff";

    private String upperCompassColor = "#fbc547";

    private String lowerCompassColor = "#ff614d";

    private int waterWidth = 100;

    private float fraction = 0f;

    private float rippleFraction = 0f;

    //水波纹以外的值动画
    private AnimatorValue animatorValue;
    //水波纹的值动画
    private AnimatorValue rippleAnimatorValue;

    private int duration = 1000;

    private int red = 153;

    private int green = 193;

    private int blue = 255;

    private float topPadding = 0f;

    public LocatingLoadingComponent setDuration(int duration) {
        this.duration = duration;
        return this;
    }

    public LocatingLoadingComponent setBackgroundColor(String backgroundColor) {
        this.backgroundColor = backgroundColor;
        return this;
    }

    public LocatingLoadingComponent setLowerCompassColor(String lowerCompassColor) {
        this.lowerCompassColor = lowerCompassColor;
        return this;
    }

    public LocatingLoadingComponent setUpperCompassColor(String upperCompassColor) {
        this.upperCompassColor = upperCompassColor;
        return this;
    }

    public LocatingLoadingComponent setRippleRGB(int red, int green, int blue) {
        this.upperCompassColor = upperCompassColor;
        return this;
    }

    public LocatingLoadingComponent setAutoStart(boolean autoStart) {
        this.autoStart = autoStart;
        return this;
    }

    public LocatingLoadingComponent setWaterWidth(int waterWidth) {
        this.waterWidth = waterWidth;
        return this;
    }

    public LocatingLoadingComponent(Context context) {
        this(context, null);
    }

    public LocatingLoadingComponent(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public LocatingLoadingComponent(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initUI();
    }

    private void initUI() {
        setupPaint();


        DrawTask drawTask = (component, canvas) -> {
            topPadding = (getHeight() - 1.7f * waterWidth) / 2f;
            drawRippleAndWaterDrop(canvas);
            drawInnerCircle(canvas);
            drawCompass(canvas);
            //todo（绘制内部的五角星，后面优化）
            //drawStars(canvas);
        };

        addDrawTask(drawTask);

        animatorValue = new AnimatorValue();
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setDuration(duration);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            fraction = (float) Math.sin(2 * Math.PI * v);
            invalidate();
        });

        rippleAnimatorValue = new AnimatorValue();
        rippleAnimatorValue.setLoopedCount(Animator.INFINITE);
        rippleAnimatorValue.setDuration(duration / 2);
        rippleAnimatorValue.setCurveType(Animator.CurveType.CUBIC_BEZIER_DECELERATION);
        rippleAnimatorValue.setValueUpdateListener((animatorValue, v) -> {
            if (v < 0.2f) {
                rippleFraction = 0.2f;
            } else {
                rippleFraction = v;
            }
        });

        if (autoStart) {
            animatorValue.start();
            rippleAnimatorValue.start();
        }
    }

    //画五角星
    private void drawStars(Canvas canvas) {
        Path path = new Path();
        mPaint.setColor(Color.CYAN);
        float[] floats = getFivePoints(100, 0, 50);
        for (int i = 0; i < floats.length - 1; i++) {
            path.lineTo(floats[i], floats[i += 1]);
        }
        canvas.drawPath(path, mPaint);
    }

    //绘制指南针
    private void drawCompass(Canvas canvas) {
        canvas.save();
        canvas.rotate(15 * fraction, getWidth() / 2f, waterWidth * 0.5f + topPadding);
        Path upperPath = new Path();
        upperPath.moveTo(getWidth() / 2f - waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        upperPath.lineTo(getWidth() / 2f + waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        upperPath.lineTo(getWidth() / 2f, waterWidth * 0.25f + topPadding);
        upperPath.close();
        mPaint.setColor(new Color(Color.getIntColor(upperCompassColor)));
        canvas.drawPath(upperPath, mPaint);
        Path lowerPath = new Path();
        lowerPath.moveTo(getWidth() / 2f - waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        lowerPath.lineTo(getWidth() / 2f + waterWidth * 0.07f, waterWidth * 0.5f + topPadding);
        lowerPath.lineTo(getWidth() / 2f, waterWidth * 0.75f + topPadding);
        lowerPath.close();
        mPaint.setColor(new Color(Color.getIntColor(lowerCompassColor)));
        canvas.drawPath(lowerPath, mPaint);
        canvas.restore();
    }

    //绘制内部的两个圆
    private void drawInnerCircle(Canvas canvas) {
        int width = getWidth();
        mPaint.setColor(new Color(Color.getIntColor("#8fbaff")));
        canvas.drawCircle(width / 2f, waterWidth * 0.5f + topPadding, waterWidth * 0.3f + waterWidth * 0.05f * fraction, mPaint);
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(width / 2f, waterWidth * 0.5f + topPadding, waterWidth * 0.3f, mPaint);
    }


    //绘制底部波纹与水滴
    private void drawRippleAndWaterDrop(Canvas canvas) {
        int width = getWidth();
        float bottomX = width / 2f;
        float bottomY = waterWidth * 1.3f + topPadding;
        //绘制底部椭圆
        int alpha;
        if (rippleFraction == 0.2f) {
            alpha = 0;
        } else {
            alpha = (int) (255 * (1 - rippleFraction));
        }
        Color ovalColor = new Color(Color.argb(alpha, red, green, blue));
        bottomOvalPaint.setColor(ovalColor);
        canvas.drawOval(new RectFloat(width / 2f - waterWidth * rippleFraction / 0.8f, bottomY - waterWidth * rippleFraction / 2.5f, width / 2f + waterWidth * rippleFraction / 0.8f, bottomY + waterWidth * rippleFraction / 2.5f), bottomOvalPaint);

        //绘制水滴上半部分
        mPaint.setColor(new Color(Color.getIntColor(backgroundColor)));
        canvas.drawArc(new RectFloat((width - waterWidth) / 2f, topPadding, (width + waterWidth) / 2f, waterWidth * 1.2f + topPadding), new Arc(0, -180, false), mPaint);
        //绘制水滴下半部分
        Path path = new Path();
        path.moveTo((width - waterWidth) / 2f, waterWidth * 0.6f + topPadding);
        path.quadTo(width / 2f - waterWidth / 2.6f, 19 / 20f * waterWidth + topPadding, bottomX, bottomY);
        path.quadTo(width / 2f + waterWidth / 2.6f, 19 / 20f * waterWidth + topPadding, (width + waterWidth) / 2f, waterWidth * 0.6f + topPadding);
        path.close();
        canvas.drawPath(path, mPaint);

    }

    private void setupPaint() {
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);

        bottomOvalPaint.setStyle(Paint.Style.STROKE_STYLE);
        bottomOvalPaint.setStrokeWidth(7f);
        bottomOvalPaint.setAntiAlias(true);
    }


    @Override
    protected void stopAnimators() {
        animatorValue.stop();
        rippleAnimatorValue.stop();
    }

    @Override
    protected void startAnimators() {
        animatorValue.start();
        rippleAnimatorValue.start();
    }

    /**
     * @param startX     起始点位置A的x轴绝对位置
     * @param startY     起始点位置A的y轴绝对位置
     * @param sideLength 五角星边的边长
     */
    private float[] getFivePoints(float startX, float startY, int sideLength) {
        float xB = 0;
        float xC = 0;
        float xD = 0;
        float xE = 0;
        float yB = 0;
        float yC = 0;
        float yD = 0;
        float yE = 0;
        double v = sideLength * Math.sin(Math.toRadians(18));
        xD = (float) (startX - v);
        xC = (float) (startX + v);
        yD = yC = (float) (startY + Math.cos(Math.toRadians(18)) * sideLength);
        yB = yE = (float) (startY + Math.sqrt(Math.pow((xC - xD), 2) - Math.pow((sideLength / 2), 2)));
        xB = startX + (sideLength / 2);
        xE = startX - (sideLength / 2);
        float[] floats = new float[]{startX, startY, xD, yD, xB, yB, xE, yE, xC, yC, startX, startY};
        return floats;
    }

}
